﻿// Type: System.Data.Objects.ObjectQuery`1
// Assembly: System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
// Assembly location: C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Data.Entity.dll

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.Common;
using System.Data.Common.Utils;
using System.Data.Entity;
using System.Data.Metadata.Edm;
using System.Data.Objects.ELinq;
using System.Data.Objects.Internal;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime;

namespace System.Data.Objects
{
  public class ObjectQuery<T> : ObjectQuery, IOrderedQueryable<T>, IQueryable<T>, IEnumerable<T>, IOrderedQueryable, IQueryable, IEnumerable, IListSource
  {
    private string _name;
    private const string DefaultName = "it";

    public string Name
    {
      [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get
      {
        return this._name;
      }
      set
      {
        EntityUtil.CheckArgumentNull<string>(value, "value");
        if (!ObjectParameter.ValidateParameterName(value))
          throw EntityUtil.Argument(System.Data.Entity.Strings.ObjectQuery_InvalidQueryName((object) value), "value");
        this._name = value;
      }
    }

    public ObjectQuery(string commandText, ObjectContext context)
      : this((ObjectQueryState) new EntitySqlQueryState(typeof (T), commandText, false, context, (ObjectParameterCollection) null, (Span) null))
    {
      context.MetadataWorkspace.ImplicitLoadAssemblyForType(typeof (T), Assembly.GetCallingAssembly());
    }

    public ObjectQuery(string commandText, ObjectContext context, MergeOption mergeOption)
      : this((ObjectQueryState) new EntitySqlQueryState(typeof (T), commandText, false, context, (ObjectParameterCollection) null, (Span) null))
    {
      EntityUtil.CheckArgumentMergeOption(mergeOption);
      this.QueryState.UserSpecifiedMergeOption = new MergeOption?(mergeOption);
      context.MetadataWorkspace.ImplicitLoadAssemblyForType(typeof (T), Assembly.GetCallingAssembly());
    }

    internal ObjectQuery(ObjectQueryState queryState)
      : base(queryState)
    {
    }

    private static bool IsLinqQuery(ObjectQuery query)
    {
      return query.QueryState is ELinqQueryState;
    }

    public ObjectQuery<T> Distinct()
    {
      if (ObjectQuery<T>.IsLinqQuery((ObjectQuery) this))
        return (ObjectQuery<T>) Queryable.Distinct<T>((IQueryable<T>) this);
      else
        return new ObjectQuery<T>(EntitySqlQueryBuilder.Distinct(this.QueryState));
    }

    public ObjectQuery<T> Except(ObjectQuery<T> query)
    {
      EntityUtil.CheckArgumentNull<ObjectQuery<T>>(query, "query");
      if (ObjectQuery<T>.IsLinqQuery((ObjectQuery) this) || ObjectQuery<T>.IsLinqQuery((ObjectQuery) query))
        return (ObjectQuery<T>) Queryable.Except<T>((IQueryable<T>) this, (IEnumerable<T>) query);
      else
        return new ObjectQuery<T>(EntitySqlQueryBuilder.Except(this.QueryState, query.QueryState));
    }

    public ObjectQuery<DbDataRecord> GroupBy(string keys, string projection, params ObjectParameter[] parameters)
    {
      EntityUtil.CheckArgumentNull<string>(keys, "keys");
      EntityUtil.CheckArgumentNull<string>(projection, "projection");
      EntityUtil.CheckArgumentNull<ObjectParameter[]>(parameters, "parameters");
      if (StringUtil.IsNullOrEmptyOrWhiteSpace(keys))
        throw EntityUtil.Argument(System.Data.Entity.Strings.ObjectQuery_QueryBuilder_InvalidGroupKeyList, "keys");
      if (StringUtil.IsNullOrEmptyOrWhiteSpace(projection))
        throw EntityUtil.Argument(System.Data.Entity.Strings.ObjectQuery_QueryBuilder_InvalidProjectionList, "projection");
      else
        return new ObjectQuery<DbDataRecord>(EntitySqlQueryBuilder.GroupBy(this.QueryState, this.Name, keys, projection, parameters));
    }

    public ObjectQuery<T> Intersect(ObjectQuery<T> query)
    {
      EntityUtil.CheckArgumentNull<ObjectQuery<T>>(query, "query");
      if (ObjectQuery<T>.IsLinqQuery((ObjectQuery) this) || ObjectQuery<T>.IsLinqQuery((ObjectQuery) query))
        return (ObjectQuery<T>) Queryable.Intersect<T>((IQueryable<T>) this, (IEnumerable<T>) query);
      else
        return new ObjectQuery<T>(EntitySqlQueryBuilder.Intersect(this.QueryState, query.QueryState));
    }

    public ObjectQuery<TResultType> OfType<TResultType>()
    {
      if (ObjectQuery<T>.IsLinqQuery((ObjectQuery) this))
        return (ObjectQuery<TResultType>) Queryable.OfType<TResultType>((IQueryable) this);
      this.QueryState.ObjectContext.MetadataWorkspace.ImplicitLoadAssemblyForType(typeof (TResultType), Assembly.GetCallingAssembly());
      Type clrOfType = typeof (TResultType);
      EdmType type = (EdmType) null;
      if (!this.QueryState.ObjectContext.MetadataWorkspace.GetItemCollection(DataSpace.OSpace).TryGetType(clrOfType.Name, clrOfType.Namespace ?? string.Empty, out type) || !Helper.IsEntityType(type) && !Helper.IsComplexType(type))
        throw EntityUtil.EntitySqlError(System.Data.Entity.Strings.ObjectQuery_QueryBuilder_InvalidResultType((object) typeof (TResultType).FullName));
      else
        return new ObjectQuery<TResultType>(EntitySqlQueryBuilder.OfType(this.QueryState, type, clrOfType));
    }

    public ObjectQuery<T> OrderBy(string keys, params ObjectParameter[] parameters)
    {
      EntityUtil.CheckArgumentNull<string>(keys, "keys");
      EntityUtil.CheckArgumentNull<ObjectParameter[]>(parameters, "parameters");
      if (StringUtil.IsNullOrEmptyOrWhiteSpace(keys))
        throw EntityUtil.Argument(System.Data.Entity.Strings.ObjectQuery_QueryBuilder_InvalidSortKeyList, "keys");
      else
        return new ObjectQuery<T>(EntitySqlQueryBuilder.OrderBy(this.QueryState, this.Name, keys, parameters));
    }

    public ObjectQuery<DbDataRecord> Select(string projection, params ObjectParameter[] parameters)
    {
      EntityUtil.CheckArgumentNull<string>(projection, "projection");
      EntityUtil.CheckArgumentNull<ObjectParameter[]>(parameters, "parameters");
      if (StringUtil.IsNullOrEmptyOrWhiteSpace(projection))
        throw EntityUtil.Argument(System.Data.Entity.Strings.ObjectQuery_QueryBuilder_InvalidProjectionList, "projection");
      else
        return new ObjectQuery<DbDataRecord>(EntitySqlQueryBuilder.Select(this.QueryState, this.Name, projection, parameters));
    }

    public ObjectQuery<TResultType> SelectValue<TResultType>(string projection, params ObjectParameter[] parameters)
    {
      EntityUtil.CheckArgumentNull<string>(projection, "projection");
      EntityUtil.CheckArgumentNull<ObjectParameter[]>(parameters, "parameters");
      if (StringUtil.IsNullOrEmptyOrWhiteSpace(projection))
        throw EntityUtil.Argument(System.Data.Entity.Strings.ObjectQuery_QueryBuilder_InvalidProjectionList, "projection");
      this.QueryState.ObjectContext.MetadataWorkspace.ImplicitLoadAssemblyForType(typeof (TResultType), Assembly.GetCallingAssembly());
      return new ObjectQuery<TResultType>(EntitySqlQueryBuilder.SelectValue(this.QueryState, this.Name, projection, parameters, typeof (TResultType)));
    }

    public ObjectQuery<T> Skip(string keys, string count, params ObjectParameter[] parameters)
    {
      EntityUtil.CheckArgumentNull<string>(keys, "keys");
      EntityUtil.CheckArgumentNull<string>(count, "count");
      EntityUtil.CheckArgumentNull<ObjectParameter[]>(parameters, "parameters");
      if (StringUtil.IsNullOrEmptyOrWhiteSpace(keys))
        throw EntityUtil.Argument(System.Data.Entity.Strings.ObjectQuery_QueryBuilder_InvalidSortKeyList, "keys");
      if (StringUtil.IsNullOrEmptyOrWhiteSpace(count))
        throw EntityUtil.Argument(System.Data.Entity.Strings.ObjectQuery_QueryBuilder_InvalidSkipCount, "count");
      else
        return new ObjectQuery<T>(EntitySqlQueryBuilder.Skip(this.QueryState, this.Name, keys, count, parameters));
    }

    public ObjectQuery<T> Top(string count, params ObjectParameter[] parameters)
    {
      EntityUtil.CheckArgumentNull<string>(count, "count");
      if (StringUtil.IsNullOrEmptyOrWhiteSpace(count))
        throw EntityUtil.Argument(System.Data.Entity.Strings.ObjectQuery_QueryBuilder_InvalidTopCount, "count");
      else
        return new ObjectQuery<T>(EntitySqlQueryBuilder.Top(this.QueryState, this.Name, count, parameters));
    }

    public ObjectQuery<T> Union(ObjectQuery<T> query)
    {
      EntityUtil.CheckArgumentNull<ObjectQuery<T>>(query, "query");
      if (ObjectQuery<T>.IsLinqQuery((ObjectQuery) this) || ObjectQuery<T>.IsLinqQuery((ObjectQuery) query))
        return (ObjectQuery<T>) Queryable.Union<T>((IQueryable<T>) this, (IEnumerable<T>) query);
      else
        return new ObjectQuery<T>(EntitySqlQueryBuilder.Union(this.QueryState, query.QueryState));
    }

    public ObjectQuery<T> UnionAll(ObjectQuery<T> query)
    {
      EntityUtil.CheckArgumentNull<ObjectQuery<T>>(query, "query");
      return new ObjectQuery<T>(EntitySqlQueryBuilder.UnionAll(this.QueryState, query.QueryState));
    }

    public ObjectQuery<T> Where(string predicate, params ObjectParameter[] parameters)
    {
      EntityUtil.CheckArgumentNull<string>(predicate, "predicate");
      EntityUtil.CheckArgumentNull<ObjectParameter[]>(parameters, "parameters");
      if (StringUtil.IsNullOrEmptyOrWhiteSpace(predicate))
        throw EntityUtil.Argument(System.Data.Entity.Strings.ObjectQuery_QueryBuilder_InvalidFilterPredicate, "predicate");
      else
        return new ObjectQuery<T>(EntitySqlQueryBuilder.Where(this.QueryState, this.Name, predicate, parameters));
    }

    public ObjectResult<T> Execute(MergeOption mergeOption)
    {
      EntityUtil.CheckArgumentMergeOption(mergeOption);
      return this.GetResults(new MergeOption?(mergeOption));
    }

    public ObjectQuery<T> Include(string path)
    {
      EntityUtil.CheckStringArgument(path, "path");
      return new ObjectQuery<T>(this.QueryState.Include<T>(this, path));
    }

    IEnumerator<T> IEnumerable<T>.GetEnumerator()
    {
      ObjectResult<T> results = this.GetResults(new MergeOption?());
      try
      {
        return results.GetEnumerator();
      }
      catch
      {
        results.Dispose();
        throw;
      }
    }

    internal override IEnumerator GetEnumeratorInternal()
    {
      return (IEnumerator) this.GetEnumerator();
    }

    internal override IList GetIListSourceListInternal()
    {
      return this.GetResults(new MergeOption?()).GetList();
    }

    internal override ObjectResult ExecuteInternal(MergeOption mergeOption)
    {
      return (ObjectResult) this.GetResults(new MergeOption?(mergeOption));
    }

    internal override Expression GetExpression()
    {
      Expression expression;
      if (!this.QueryState.TryGetExpression(out expression))
        expression = (Expression) Expression.Constant((object) this);
      Type requiredType = typeof (ObjectQuery<T>);
      if (this.QueryState.UserSpecifiedMergeOption.HasValue)
      {
        MethodInfo method = requiredType.GetMethod("MergeAs", BindingFlags.Instance | BindingFlags.NonPublic);
        expression = (Expression) Expression.Call(TypeSystem.EnsureType(expression, requiredType), method, new Expression[1]
        {
          (Expression) Expression.Constant((object) this.QueryState.UserSpecifiedMergeOption.Value)
        });
      }
      if (this.QueryState.Span != null)
      {
        MethodInfo method = requiredType.GetMethod("IncludeSpan", BindingFlags.Instance | BindingFlags.NonPublic);
        expression = (Expression) Expression.Call(TypeSystem.EnsureType(expression, requiredType), method, new Expression[1]
        {
          (Expression) Expression.Constant((object) this.QueryState.Span)
        });
      }
      return expression;
    }

    internal ObjectQuery<T> MergeAs(MergeOption mergeOption)
    {
      throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.ELinq_MethodNotDirectlyCallable);
    }

    internal ObjectQuery<T> IncludeSpan(Span span)
    {
      throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.ELinq_MethodNotDirectlyCallable);
    }

    private ObjectResult<T> GetResults(MergeOption? forMergeOption)
    {
      this.QueryState.ObjectContext.EnsureConnection();
      try
      {
        return this.QueryState.GetExecutionPlan(forMergeOption).Execute<T>(this.QueryState.ObjectContext, this.QueryState.Parameters);
      }
      catch
      {
        this.QueryState.ObjectContext.ReleaseConnection();
        throw;
      }
    }
  }
}
